home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
asmutil
/
asm_n_z.zip
/
WAITASEC.ASM
< prev
next >
Wrap
Assembly Source File
|
1986-02-05
|
15KB
|
450 lines
; WAITASEC.ASM -- Holds and Recalls Scrolling Screens
; ============
; (C) Copyright Charles Petzold, 1985
;
; COM file format
;
CSEG Segment
Assume CS:CSEG
Org 0080h
SWAP Label Byte ; Use this area for line swapping
Org 0100h
Entry: Jmp Initialize ; Entry: Jump over resident part
; All Data
; --------
Cols equ 80 ; You may want to set this to 40
ScrollLock equ 70 ; Scan code of Scroll Lock key
NumberOfScreens dw 8 ; Can be set up to 15 for 80-column
db '(C) Copyright Charles Petzold, 1985'
DisplaySegment dw ? ; Display address set by VideoCheck
OldInterrupt9 dd ? ; Saved address of real Interrupt 9
OldInterrupt10 dd ? ; Ditto for Interrupt 10h
TopHoldAddr dw Offset HoldArea ; Address of top of Hold area
BotHoldAddr dw ? ; Address of bottom of Hold area
SavePointer dw Offset HoldArea ; Points to where text is saved
RecallPointer dw Offset HoldArea ; Points to where text is recalled
LockStateOn db 0 ; Flag for lock or no lock
ScrollLockDown db 0 ; Current state of Scroll Lock key
KeyDispatch dw Home,Up,PgUp ; Dispatch addresss of routines
dw 5 Dup (Dummy) ; for cursor movement within
dw End,Down,PgDn ; recalled displays
; Intercept of Interrupt 10h -- BIOS Video Call
; --------------------------
NewInterrupt10: Cmp AX,0601h ; Check if this is a 1 line scroll up
Jne NoNeedToBother ; No, just continue to real interrupt
Cmp CX,0 ; Check if this is upper left corner
Jne NoNeedToBother ; No, don't want to touch it
Cmp DL,Cols - 1 ; Check if DL is right hand side
Jne NoNeedToBother ; Another obstacle that shuts us out
Call VideoCheck ; Returns Carry if graphics
Jc NoNeedToBother ; So we drop out here if Carry is set
Sti ; Allow interrupts
Cld ; And set direction to forward
Push CX ; Save all the registers we'll use
Push SI
Push DI
Push DS
Push ES
Push CS ; Push this code segment
Pop ES ; So we can set ES to it
Mov DI,CS:[SavePointer] ; This is the destination
Mov DS,CS:[DisplaySegment] ; This is the source segment
Sub SI,SI ; Source is top of display
Mov CX,Cols ; The number of characters
Call VideoOff ; Turn off light show if color
Rep Movsw ; Move 'em in!
Call VideoOn ; Turn display back on
Cmp DI,CS:[BotHoldAddr] ; Check the new destination
Jb NotAtBotYet ; Jump if it hasn't wrapped yet
Mov DI,CS:[TopHoldAddr] ; Set it to top if it has
NotAtBotYet: Mov CS:[SavePointer],DI ; And save it anyway
Pop ES ; Pop the registers we saved
Pop DS
Pop DI
Pop SI
Pop CX
NoNeedToBother: Jmp CS:[OldInterrupt10] ; And do the interrupt for real
; Intercept of Interrupt 9h -- Hardware Keyboard Interrupt
; --------------------------------------------------------
NewInterrupt9: Sti ; Allow other interrupts
Push AX ; Save the register for awhile
In AL,60h ; Get the pressed key scan code
Cmp AL,ScrollLock ; Check if it's the Scroll Lock
Jz GottaScrollLock ; If so, do special routine
Cmp AL,128 + ScrollLock ; Check if scroll lock release
Jz ScrollLockRlse ; Another special routine
Jmp AnyOtherKey ; Otherwise, it's some other key
; Scroll Lock key depressed
; -------------------------
GottaScrollLock:Mov CS:[ScrollLockDown],1 ; Flag Scroll Lock as depressed
Cmp CS:[LockStateOn],1 ; See if we're locked now
Jz AnyOtherKey ; If so, will just reset
Mov AH,2 ; Do keyboard interrupt
Int 16h ; to get shift states
Test AL,04 ; See if Ctrl has been pressed
Jnz NormalProcess ; Process normally if Break
Call VideoCheck ; See if video is OK for recall
Jc NormalProcess ; If not, ignore the key
Mov CS:[LockStateOn],1 ; Lock state now ON
Push CS:[SavePointer] ; Transfer value of SavePointer
Pop CS:[RecallPointer] ; ... to RecallPointer
PushF ; Simulate an interrupt
Call CS:[OldInterrupt9] ; Let Scroll Lock Register
Call VideoOn ; Video might be off - turn on
HoldingPattern: Cmp CS:[LockStateOn],1 ; Wait in this loop ...
Jz HoldingPattern ; ... until out of lock state
Jmp NormalProcess ; Then process last key
; Scroll Lock key released
; ------------------------
ScrollLockRlse: Mov CS:[ScrollLockDown],0 ; Register Scroll Lock release
Cmp CS:[LockStateOn],1 ; See if in lock state
Jnz NormalProcess ; If not, just process key
Mov AX,CS:[SavePointer] ; Check if the screen is in
Cmp AX,CS:[RecallPointer] ; normal position
Jnz NormalProcess ; If not, just process key
Mov CS:[LockStateOn],0 ; If so, turn lock state OFF
Pop AX ; Restore register
IRet ; Return to holding pattern
; All other keys
; --------------
AnyOtherKey: Cmp CS:[LockStateOn],1 ; For other keys, just do
Jnz NormalProcess ; normal processing if not lock
Call NowInLockState ; But call routine if locked
Pop AX ; Restore register
IRet ; Return to holding pattern
NormalProcess: Pop AX ; Get back the register
Jmp CS:[OldInterrupt9] ; Let the key process
; Routine for other keys during lock state (AL = Scan Code)
; ---------------------------------------------------------
NowInLockState: Cld ; String moves generally forward
Push CX ; We use all these registers
Push DX
Push SI
Push DI
Push DS
Push ES
Mov DX,CS ; Get value of CS
Mov DS,DX ; Set DS and
Mov ES,DX ; ES to this segment
Assume DS:CSEG, ES:CSEG ; And tell the assembler
Mov AH,AL ; AH is actual scan code
And AL,7Fh ; AL has release byte off
Sub AL,71 ; Subtract the 'Home' key value
Jb WrongKey ; No good if below
Cmp AL,(81 - 71) ; Above the 'PgDn' key?
Ja WrongKey ; You're not right either
Cmp AL,(73 - 71) ; Check if under or = 'PgUp'
Jbe AllRightKey ; Ok for this key
Cmp AL,(79 - 71) ; Check if over or = 'End'
Jae AllRightKey ; You pass too
WrongKey: Cmp [ScrollLockDown],1 ; See if scroll lock is down
Jz ResetKeyboard ; If so, just ignore the key
Call End ; If not, restore the display
Mov [LockStateOn],0 ; Turn off the lock state
Jmp KeyReturn ; And get out quickly
AllRightKey: Test AH,80h ; See if cursor key is release
Jnz ResetKeyboard ; If so, ignore the key
Cbw ; Convert scan code to word
Add AX,AX ; Double it because word access
Mov SI,AX ; Set SI to it
Call [KeyDispatch + SI] ; And do the routine
ResetKeyboard: In AL,61h ; These instructions
Mov AH,AL ; reset the keyboard
Or AL,80h
Out 61h,AL
Mov AL,AH
Out 61h,AL
Cli ; Disable interrupts
Mov AL,20h ; to reset the interrupt
Out 20h,AL ; controller
KeyReturn: Pop ES ; Get back all the pushes
Pop DS
Pop DI
Pop SI
Pop DX
Pop CX
Ret ; Return to previous routine
; Routines to scan up through saved display
; -----------------------------------------
Home: Mov CX,0FFFFh ; 'Home' key -- "infinite" lines up
Jmp Short GoingUp ; Do it
Up: Mov CX,1 ; 'Up' key -- 1 line up
Jmp Short GoingUp ; Go to it
PgUp: Mov CX,25 ; 'PgUp' key -- 25 lines (1 screen) up
GoingUp: Mov AX,[RecallPointer] ; Points to the text source
Cmp AX,[TopHoldAddr] ; Check if it's at the top
Ja NotScanUpTop ; If not there, no problem
Mov AX,[BotHoldAddr] ; Otherwise must wrap around
NotScanUpTop: Sub AX,Cols * 2 ; Go back one line for recall
Cmp AX,[SavePointer] ; Check if cycled through yet
Je EndGoingUp ; If so, abort this routine
Mov [RecallPointer],AX ; Save the new pointer value
Push CX ; And save our counter
Mov SI,2 * 24 * Cols ; Set source to bottom line
Call DisplayToSwap ; Transfer it to SWAP area
Mov SI,2 * 24 * Cols - 2 ; End of penultimate line
Mov DI,2 * 25 * Cols - 2 ; End of last line
Std ; Backwards string transfer
Call ScrollDisplay ; Do the screen scroll
Cld ; Direction back to forward
Mov DI,0 ; Destination is top line
Call HoldToDisplay ; Move line to display
Call SwapToHold ; And SWAP line to hold
Pop CX ; Get back the counter
Loop GoingUp ; And do CX time